#pragma once
#include <iostream>
#include <string>
#include <cassert>
#include <functional>
#include "epoll.hpp"
#include "Sock.hpp"
#include "Log.hpp"

const static int gport = 8888;

using func_t = std::function<std::string (std::string)>;

class EpollServer
{
    const static int gnum = 64;

public:
    EpollServer(func_t func, uint16_t port = gport) : func_(func), port_(port)
    {
    }
    void InitServer()
    {
        listensock_.Socket();
        listensock_.Bind(port_);
        listensock_.Listen();
        epoller_.Create();

        logMessage(Debug, "init server success");
    }
    int Start()
    {
        // 1. 将listensock添加到epoll中！
        bool r = epoller_.AddEvent(listensock_.Fd(), EPOLLIN);
        assert(r);
        (void)r;

        int timeout = -1;
        while (true)
        {
            int n = epoller_.Wait(revs_, gnum, timeout);
            switch (n)
            {
            case 0:
                logMessage(Debug, "timeout...");
                break;
            case -1:
                logMessage(Warning, "epoll_wait failed");
                break;
            default:
                logMessage(Debug, "有%d个事件就绪了", n);
                HandlerEvents(n);
                break;
            }
        }
    }
    void HandlerEvents(int num)
    {
        for (int i = 0; i < num; i++)
        {
            int fd = revs_[i].data.fd;
            uint32_t events = revs_[i].events;

            logMessage(Debug, "当前正在处理%d上的%s", fd, (events&EPOLLIN) ? "EPOLLIN" : "OTHER");

            if (events & EPOLLIN)
            {
                if (fd == listensock_.Fd())
                {
                    // 1. 新连接到来
                    // logMessage(Debug, "get a new link ...");
                    std::string clientip;
                    uint16_t clientport;
                    int sock = listensock_.Accept(&clientip, &clientport);
                    if (sock < 0)
                        continue;
                    logMessage(Debug, "%s:%d 已经连上了服务器了", clientip.c_str(), clientport);
                    // 1.1 此时在这里，我们能不能进行recv/read ? 不能，只有epoll知道sock上面的事件情况，将sock添加到epoll中
                    bool r = epoller_.AddEvent(sock, EPOLLIN);
                    assert(r);
                    (void)r;
                }
                else
                {
                    // 我们目前无法保证我们读到一个完整的报文
                    // 为什么？完整报文由应用层协议规定, 本质就是你没有应用层协议！
                    // 怎办？自定义应用层协议
                    char request[1024];
                    ssize_t s = recv(fd, request, sizeof(request) - 1, 0); 
                    if (s > 0)
                    {
                        request[s-1] = 0; // \r\n
                        request[s-2] = 0; // \r\n

                        std::string response = func_(request);

                        send(fd, response.c_str(), response.size(), 0);
                    }
                    else
                    {
                        if (s == 0)
                            logMessage(Info, "client quit ...");
                        else
                            logMessage(Warning, "recv error, client quit ...");
                        // 在处理异常的时候，先从epoll中移除，然后再关闭
                        epoller_.DelEvent(fd);
                        close(fd);
                    }
                } // else 读取事件
            }     // fi : 读事件就绪
        }
    }
    ~EpollServer()
    {
        listensock_.Close();
        epoller_.Close();
    }

private:
    uint16_t port_;
    Sock listensock_;
    Epoller epoller_;
    struct epoll_event revs_[gnum];
    func_t func_;
};